SpringBoot整合SpringSecurity权限控制(动态拦截url+单点登录)

您所在的位置:网站首页 springboot shiro jwt 单点登录 SpringBoot整合SpringSecurity权限控制(动态拦截url+单点登录)

SpringBoot整合SpringSecurity权限控制(动态拦截url+单点登录)

2023-04-05 23:45| 来源: 网络整理| 查看: 265

前言

Spring Security是一个功能强大且可高度自定义的身份验证和访问控制框架。它是保护基于Spring的应用程序的事实上的标准。

Spring Security是一个专注于为Java应用程序提供身份验证和授权的框架。与所有Spring项目一样,Spring Security的真正强大之处在于它可以轻松扩展以满足自定义要求。

项目搭建引入依赖 org.springframework.boot spring-boot-starter-security io.jsonwebtoken jjwt 0.9.1

登录拦截全局配置

@Configuration public class WebSecurityConfigure extends WebSecurityConfigurerAdapter { @Resource private UrlAuthenticationEntryPoint authenticationEntryPoint; //自定义未登录时:返回状态码401 @Resource private UrlAuthenticationSuccessHandler authenticationSuccessHandler; //自定义登录成功处理器并生成token:响应状态码200及token @Resource private UrlAuthenticationFailureHandler authenticationFailureHandler; //自定义登录失败处理器:返回状态码402 @Resource private UrlAccessDeniedHandler accessDeniedHandler; //自定义权限不足处理器:返回状态码403 @Resource private UrlLogoutSuccessHandler logoutSuccessHandler; //自定义注销成功处理器:返回状态码200 @Resource private SelfAuthenticationProvider authenticationProvider; //自定义登录认证 @Resource private SelfFilterInvocationSecurityMetadataSource filterInvocationSecurityMetadataSource; //动态获取url权限配置 @Resource private SelfAccessDecisionManager accessDecisionManager; //自定义权限判断管理器 @Resource private AuthenticationDetailsSource authenticationDetailsSource; //身份验证详细信息源 @Resource private JwtAuthorizationTokenFilter authorizationTokenFilter; //JwtToken解析并生成authentication身份信息过滤器 @Override public void configure(WebSecurity web) { // web.ignoring().antMatchers("/connect/**"); //无条件允许访问 web.ignoring().antMatchers("/common/**"); //无条件允许访问 } @Override protected void configure(AuthenticationManagerBuilder auth) { auth.authenticationProvider(authenticationProvider); //自定义登录认证 } @Override protected void configure(HttpSecurity http) throws Exception { // 关闭csrf验证(防止跨站请求伪造攻击) http.csrf().disable(); // JwtToken解析并生成authentication身份信息过滤器 http.addFilterBefore(authorizationTokenFilter, UsernamePasswordAuthenticationFilter.class); // 未登录时:返回状态码401 http.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint); // 无权访问时:返回状态码403 http.exceptionHandling().accessDeniedHandler(accessDeniedHandler); // url权限认证处理 http.antMatcher("/**").authorizeRequests() // .antMatchers("/security/user/**").hasRole("ADMIN") //需要ADMIN角色才可以访问 // .antMatchers("/connect").hasIpAddress("127.0.0.1") //只有ip[127.0.0.1]可以访问'/connect'接口 .anyRequest() //其他任何请求 .authenticated() //都需要身份认证 .withObjectPostProcessor(new ObjectPostProcessor() { @Override public O postProcess(O o) { o.setSecurityMetadataSource(filterInvocationSecurityMetadataSource); //动态获取url权限配置 o.setAccessDecisionManager(accessDecisionManager); //权限判断 return o; } }); // 将session策略设置为无状态的,通过token进行登录认证 http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); // 开启自动配置的登录功能 http.formLogin() //开启登录 // .loginPage("/login") //登录页面(前后端不分离) .loginProcessingUrl("/nonceLogin") //自定义登录请求路径(post) .usernameParameter("username").passwordParameter("password") //自定义登录用户名密码属性名,默认为username和password // .successForwardUrl("/index") //登录成功后的url(post,前后端不分离) // .failureForwardUrl("/error") //登录失败后的url(post,前后端不分离) .successHandler(authenticationSuccessHandler) //验证成功处理器(前后端分离):生成token及响应状态码200 .failureHandler(authenticationFailureHandler) //验证失败处理器(前后端分离):返回状态码402 .authenticationDetailsSource(authenticationDetailsSource); //身份验证详细信息源(登录验证中增加额外字段) // 开启自动配置的注销功能 http.logout() //用户注销, 清空session .logoutUrl("/nonceLogout") //自定义注销请求路径 // .logoutSuccessUrl("/bye") //注销成功后的url(前后端不分离) .logoutSuccessHandler(logoutSuccessHandler); //注销成功处理器(前后端分离):返回状态码200 } }

JwtToken解析并生成authentication身份信息过滤器

@SuppressWarnings("unchecked") @Slf4j @Component public class JwtAuthorizationTokenFilter extends OncePerRequestFilter { @Value("${jwt.token-header-key}") private String tokenHeaderKey; //token请求头Key @Value("${jwt.token-prefix}") private String tokenPrefix; //token前缀 @Value("${jwt.token-secret}") private String tokenSecret; //token秘钥 /** * 解析token并生成authentication身份信息 */ @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { String token = request.getHeader(tokenHeaderKey); log.info("JwtAuthorizationTokenFilter >> token:{}", token); if (null == token || !token.startsWith(tokenPrefix + " ")) { chain.doFilter(request, response); return; } Claims claims; try { // 解析token claims = Jwts.parser().setSigningKey(tokenSecret).parseClaimsJws(token.replace(tokenPrefix + " ", "")).getBody(); } catch (Exception e) { log.error("JwtToken validity!! error={}", e.getMessage()); chain.doFilter(request, response); return; } String username = claims.getSubject(); List roles = claims.get("role", List.class); List authorities = roles.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList()); if (null != username) { // 生成authentication身份信息 UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(username, null, authorities); SecurityContextHolder.getContext().setAuthentication(authentication); } chain.doFilter(request, response); } }

自定义登录认证

@Slf4j @Component public class SelfAuthenticationProvider implements AuthenticationProvider { @Resource private SelfUserDetailsService selfUserDetailsService; @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { log.info("authentication >> {}", JSONObject.toJSONString(authentication, SerializerFeature.WriteMapNullValue)); CustomWebAuthenticationDetails customWebAuthenticationDetails = (CustomWebAuthenticationDetails) authentication.getDetails(); //获取身份验证详细信息 // String remoteAddress = customWebAuthenticationDetails.getRemoteAddress(); // String sessionId = customWebAuthenticationDetails.getSessionId(); // System.out.println("remoteAddress >> " + remoteAddress); // System.out.println("sessionId >> " + sessionId); // System.out.println("details >> " + JSONObject.toJSONString(customWebAuthenticationDetails, SerializerFeature.WriteMapNullValue)); System.out.println("macAddress >> " + customWebAuthenticationDetails.getMacAddress()); //用于校验mac地址白名单(这里只是打个比方,登录验证中增加的额外字段) String username = (String) authentication.getPrincipal(); //表单输入的用户名 String password = (String) authentication.getCredentials(); //表单输入的密码 UserDetails userInfo = selfUserDetailsService.loadUserByUsername(username); boolean matches = new BCryptPasswordEncoder().matches(password, userInfo.getPassword()); //校验用户名密码 if (!matches) { throw new BadCredentialsException("The password is incorrect!!"); } return new UsernamePasswordAuthenticationToken(username, userInfo.getPassword(), userInfo.getAuthorities()); } @Override public boolean supports(Class aClass) { return true; } }

自定义用户认证

@Component public class SelfUserDetailsService implements UserDetailsService { @Resource private UserService userService; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { SelfUserDetails userInfo = new SelfUserDetails(); userInfo.setUsername(username); //任意登录用户名 String password = userService.findPasswordByUsernameAfterValidTime(username); if (ObjectUtils.isEmpty(password)) { throw new UsernameNotFoundException("User name" + username + "not find!!"); } userInfo.setPassword(password); //从数据库获取密码 Set authoritiesSet = new HashSet(); List roles = userService.findRoleNameByUsername(username); for (String roleName : roles) { SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority(roleName); //用户拥有的角色 authoritiesSet.add(simpleGrantedAuthority); } userInfo.setAuthorities(authoritiesSet); return userInfo; } }

自定义web身份验证详细信息(用于登录验证中增加额外参数)

class CustomWebAuthenticationDetails extends WebAuthenticationDetails implements Serializable { private String macAddress; CustomWebAuthenticationDetails(HttpServletRequest httpServletRequest) { super(httpServletRequest); // Enumeration headerNames = httpServletRequest.getHeaderNames(); // while (headerNames.hasMoreElements()) { // String s = headerNames.nextElement(); // String header = httpServletRequest.getHeader(s); // System.out.println(s + ": " + header); // } macAddress = httpServletRequest.getParameter("macAddress"); } String getMacAddress() { return macAddress; } }

自定义身份验证详细信息源

@Component public class CustomAuthenticationDetailsSource implements AuthenticationDetailsSource { @Override public WebAuthenticationDetails buildDetails(HttpServletRequest httpServletRequest) { return new CustomWebAuthenticationDetails(httpServletRequest); } }

动态获取url权限配置

@Slf4j @Component public class SelfFilterInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource { @Resource private UserService userService; private AntPathMatcher antPathMatcher = new AntPathMatcher(); @Override public Collection getAttributes(Object o) throws IllegalArgumentException { Set set = new HashSet(); // 获取请求地址 String requestUrl = ((FilterInvocation) o).getRequestUrl(); log.info("requestUrl >> {}", requestUrl); List menuUrl = userService.findAllMenuUrl(); for (String url : menuUrl) { if (antPathMatcher.match(url, requestUrl)) { List roleNames = userService.findRoleNameByMenuUrl(url); //当前请求需要的权限 roleNames.forEach(roleName -> { SecurityConfig securityConfig = new SecurityConfig(roleName); set.add(securityConfig); }); } } if (ObjectUtils.isEmpty(set)) { return SecurityConfig.createList("ROLE_LOGIN"); } return set; } @Override public Collection getAllConfigAttributes() { return null; } @Override public boolean supports(Class aClass) { return FilterInvocation.class.isAssignableFrom(aClass); } }

自定义权限判断管理器

@Slf4j @Component public class SelfAccessDecisionManager implements AccessDecisionManager { @Override public void decide(Authentication authentication, Object o, Collection collection) throws AccessDeniedException, InsufficientAuthenticationException { // 当前请求需要的权限 log.info("collection:{}", collection); // 当前用户所具有的权限 Collection


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3